home *** CD-ROM | disk | FTP | other *** search
/ CD Ware Multimedia 1994 November / Cd Ware (Nro. 2) - Epimundo.iso / DOS / PG / PMAPP.ZIP / DPMIRUN.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-22  |  10.9 KB  |  416 lines

  1. //=====================================================================
  2. //
  3. //  dpmirun.cpp
  4. //
  5. //  This is the loader for protected mode dos applications.
  6. //
  7. //  This is very dependant on Borland C++.
  8. //  It must be compiled in small model.
  9. //
  10. //  It requires DPMI to work.
  11. //
  12. //  Copyright (c) 1994, Kevin Morgan, All rights reserved.
  13. //
  14. //=====================================================================
  15.  
  16. #define GLOBALS
  17. #include "dpmirun.h"
  18.  
  19. //=====================================================================
  20. //
  21. //  GpfRegs
  22. //
  23. //  This is what our stack looks like after we have entered our
  24. //  exception handler.
  25. //
  26. //  This is heavily dependant on order that Borland C pushes
  27. //  registers onto the stack.
  28. //
  29. //=====================================================================
  30. struct GpfRegs {
  31.     WORD Rbp;
  32.     WORD Rdi;
  33.     WORD Rsi;
  34.     WORD Rds;
  35.     WORD Res;
  36.     WORD Rdx;
  37.     WORD Rcx;
  38.     WORD Rbx;
  39.     WORD Rax;
  40.     WORD Rip;
  41.     WORD Rcs;
  42.     WORD Rfl;
  43.     WORD faultip;
  44.     WORD faultcs;
  45.     WORD flags;
  46.     WORD sp;
  47.     WORD ss;
  48. };
  49.  
  50.  
  51. //=====================================================================
  52. //
  53. //  global variables
  54. //
  55. //=====================================================================
  56.  
  57.  
  58. jmp_buf trapbuf;        // for a long jump to our exception handler
  59.  
  60. GpfRegs gpfRegs;        // registers at the time of the exception
  61.  
  62.  
  63. //=====================================================================
  64. //
  65. //  printDpmiException
  66. //
  67. //  print out our machine state, and attempt to do a traceback
  68. //
  69. //=====================================================================
  70. void printDpmiException(ModuleLoader *module)
  71. {
  72.     int i;
  73.     GpfRegs * pGpfRegs  = &gpfRegs;
  74.  
  75.     printf("\nProcessor Exception:\n");
  76.     printf("CS=%04x, DS=%04x  SS:SP=%04x:%04x\n",  _CS, _DS, _SS, _SP);
  77.  
  78.     printf("bp=%04x, di=%04x, si=%04x ds=%04x\n",
  79.         pGpfRegs->Rbp,
  80.         pGpfRegs->Rdi,
  81.         pGpfRegs->Rsi,
  82.         pGpfRegs->Rds);
  83.     printf("es=%04x, dx=%04x, cx=%04x bx=%04x\n",
  84.         pGpfRegs->Res,
  85.         pGpfRegs->Rdx,
  86.         pGpfRegs->Rcx,
  87.         pGpfRegs->Rbx);
  88.     printf("ax=%04x, ip=%04x, cs=%04x fl=%04x\n",
  89.         pGpfRegs->Rax,
  90.         pGpfRegs->Rip,
  91.         pGpfRegs->Rcs,
  92.         pGpfRegs->Rfl);
  93.  
  94.     printf("Fault CS:IP = %04x:%04x Flags=%04x\n",
  95.         pGpfRegs->faultcs,
  96.         pGpfRegs->faultip,
  97.         pGpfRegs->flags);
  98.  
  99.     printf("ss:sp = %04x:%04x\n",
  100.         pGpfRegs->ss,
  101.         pGpfRegs->sp);
  102.  
  103.     jmp_buf savetrap;
  104.     memcpy(savetrap, trapbuf, sizeof(jmp_buf));
  105.  
  106.     if (setjmp(trapbuf)==0) {   // a fault here is ok
  107.         printf("\nStack traceback follows:\n");
  108.         {
  109.             char *faultDescr = module->describeFaultPc(
  110.                                     pGpfRegs->faultcs, pGpfRegs->faultip);
  111.             printf("Fault at  %s\n", faultDescr);
  112.         }
  113.         unsigned bp = pGpfRegs->Rbp;
  114.         for (i=0;i<20;i++) {
  115.             unsigned far *p = (unsigned far *) MK_FP(pGpfRegs->ss, bp);
  116.             char *faultDescr = module->describeFaultPc(
  117.                                     p[2], p[1]);
  118.             printf("call from %s\n", faultDescr);
  119.             if (p[0]<=bp) break;
  120.             if (p[0]==0xffff) break;
  121.             bp = p[0];
  122.         }
  123.     }
  124.     memcpy(trapbuf, savetrap, sizeof(jmp_buf));
  125. }
  126.  
  127.  
  128. //=====================================================================
  129. //
  130. //  installExceptionHandler
  131. //
  132. //  Install an exception handler to handle all protected mode processor
  133. //  exceptions.
  134. //
  135. //=====================================================================
  136. void installExceptionHandler(DpmiInterruptVector v)
  137. {
  138.     memset(&gpfRegs, 0, sizeof(gpfRegs));
  139.     FP_SEG(v) = _CS;
  140.     int i;
  141.     for (i=0;i<32;i++)
  142.         Dpmi.setExceptionHandler(i, v);
  143.     /*
  144.     Dpmi.setExceptionHandler( 0, v);
  145.     Dpmi.setExceptionHandler( 6, v);
  146.     Dpmi.setExceptionHandler( 7, v);
  147.     Dpmi.setExceptionHandler( 9, v);
  148.     Dpmi.setExceptionHandler(12, v);
  149.     Dpmi.setExceptionHandler(13, v);
  150.     */
  151. //    dprintf("exception handler traps set\n");
  152. }
  153.  
  154. //=====================================================================
  155. //
  156. //  patchExceptionHandler
  157. //
  158. //  Before we can install a protected mode interrupt handler, we
  159. //  need to modify the interrupt procedure's prolog, because of
  160. //  the way BorlandC generates code...
  161. //
  162. //  This is very specific to this implementation
  163. //  and very easy to break!
  164. //
  165. //  In the prolog for Borland C interrupt procedures contains
  166. //  code to push the registers, and load DS with DGROUP.
  167. //
  168. //          ...
  169. //          MOV AX, DGROUP
  170. //          MOV DS, AX
  171. //          ...
  172. // 
  173. //  The problem is that this is compiled in with the
  174. //  DGROUP value of our real mode data segment.
  175. //
  176. //  Since this is a protected mode interrupt handler,
  177. //  we need that to be the protected mode selector
  178. //  for our data segment (not known till run time).
  179. //
  180. //  So we actually modify our code at run time to
  181. //  have the right value.
  182. //
  183. //  To accomplish this, we create a writeable alias selector,
  184. //  modify the code, and get rid of the alias.
  185. //
  186. //=====================================================================
  187. void patchExceptionHandler(DpmiInterruptVector v)
  188. {
  189.     unsigned WriteableCS;
  190.     unsigned far *p = (unsigned far *) v;
  191.  
  192.     if (Dpmi.createAlias(_CS, WriteableCS)!=DPMI_OK) {
  193.         printf("patchExceptionHandler: cannot create CS alias\n");
  194.         return;
  195.     }
  196.  
  197.     FP_SEG(p) = WriteableCS;
  198.     p[5] = _DS;
  199.     Dpmi.freeSelector(WriteableCS);
  200. }
  201.  
  202. //=====================================================================
  203. //
  204. //  copyArgs
  205. //
  206. //  copy the argv and envp arrays. Mainly needed because we need to
  207. //  convert from an array of near pointers to an array of far pointers.
  208. //
  209. //=====================================================================
  210. char far * far * copyArgs(int num, char **argv)
  211. {
  212.     if (num==0) {
  213.         char **p = argv;
  214.         while (*p++) num++;
  215.     }
  216.     char far * far * table = new char far * [num+1];
  217.     int i;
  218.     for (i=0;i<num;i++)
  219.         table[i] = argv[i];
  220.     table[num] = 0;
  221.     return table;
  222. }
  223.  
  224. //=====================================================================
  225. //
  226. //  ctrl_c
  227. //
  228. //  This is a routine to catch Control-C interrupts
  229. //  
  230. //
  231. //=====================================================================
  232. void far interrupt ctrl_c(...)
  233. {
  234.     GpfRegs far * pGpfRegs  = (GpfRegs far *) MK_FP(_SS, _BP);
  235.     _fmemcpy( &gpfRegs, pGpfRegs, sizeof(gpfRegs) );
  236.     longjmp(trapbuf,2);
  237. }
  238.  
  239. //=====================================================================
  240. //
  241. //  dpmiException
  242. //
  243. //  This is a routine to catch protected mode processor exceptions.
  244. //  
  245. //
  246. //=====================================================================
  247. void far interrupt dpmiException(...)
  248. {
  249.     GpfRegs far * pGpfRegs  = (GpfRegs far *) MK_FP(_SS, _BP);
  250.     _fmemcpy( &gpfRegs, pGpfRegs, sizeof(gpfRegs) );
  251.     longjmp(trapbuf,1);
  252. }
  253.  
  254. //=====================================================================
  255. //
  256. //  callMain
  257. //
  258. //  Start executing the program we just loaded.
  259. //
  260. //  We allocate a protected mode stack for the new program,
  261. //  copy argument and environment variables, switch to the
  262. //  new stack, and call the program's entrypoint passing
  263. //  argc, argv, and envp.
  264. //
  265. //=====================================================================
  266. void callMain(ModuleLoader *module, void far *startCsIp, int argc, char **argv, char **envp)
  267. {
  268.     const int StackSize = 4096;
  269.     static char far *stk = (char far *) module->getStack(StackSize);
  270.     if (!stk) {
  271.         Dpmi.fail("cannot allocate protected mode stack\n");
  272.         return;
  273.     }
  274.  
  275.     stk += (StackSize-32);
  276.  
  277.     static int (_far *mainline)(int, char far * far *, char far * far *);
  278.     mainline = ( int (_far *)(int, char far * far *, char far * far *) ) startCsIp;
  279.  
  280.     static char far* far* newargv = copyArgs(argc, argv);
  281.  
  282.     static char far* far* newenvp = copyArgs(0, envp);
  283.  
  284.     static int newargc = argc;
  285.  
  286.     // switch stacks 
  287.     asm {
  288.         mov ax, word ptr stk
  289.         mov bx, word ptr stk+2
  290.         mov ss,bx
  291.         mov sp,ax
  292.         push ds
  293.     }
  294.     
  295.     (*mainline)(newargc,newargv,newenvp);
  296.  
  297.     asm {
  298.         pop ds
  299.     }
  300.     longjmp(trapbuf,3);
  301. }
  302.  
  303.  
  304. //=====================================================================
  305. //
  306. //  protectedMain
  307. //
  308. //  This is the protected mode mainline.
  309. //  We set up exception handler, load the program and run it.
  310. //=====================================================================
  311. int protectedMain(int argc, char *argv[], char *envp[])
  312. {
  313.     if (argc<2) {
  314.         printf("usage: dpmirun filename ...\n");
  315.         Dpmi.dosExit(1);
  316.     }
  317.  
  318.     ModuleLoader *module = newModuleLoader();
  319.  
  320.     static char *where;
  321.  
  322.     where = "before execution\n";
  323.     if (setjmp(trapbuf)!=0) {
  324.         puts(where);
  325.         Dpmi.fail("Exception encountered before execution\n");
  326.     }
  327.  
  328.     patchExceptionHandler( ctrl_c );
  329.     Dpmi.setProtVect(0x23, ctrl_c); // install ctrl_c handler
  330.  
  331.     where = "patch exception handler";
  332.     patchExceptionHandler( dpmiException);
  333.  
  334.     where = "setup exception handler";
  335.     installExceptionHandler(dpmiException);
  336.  
  337.     where = "error loading executable";
  338.     module->loadExecutable(argv[1]);
  339.  
  340.     where = "error adjusting selectors";
  341.     module->adjustSelectors();
  342.  
  343.     where = "error getting entry point";
  344.     void _far *entryPoint = module->entryPoint();
  345.  
  346.     where = "error check loadErrors";
  347.     if (module->loadErrors()) {
  348.         printf("cannot execute because of load errors\n");
  349.         return 0;
  350.     }
  351.  
  352.     where = "reset traps";
  353.     switch (setjmp(trapbuf)) {
  354.         case 0:
  355.         {
  356.             flushall();
  357.  
  358.             // strip off the loader's name
  359.             argc--;
  360.             argv++;
  361.             callMain(module, entryPoint, argc, argv, envp);
  362.             break;
  363.         }
  364.         case 1:
  365.         {
  366.             if (setjmp(trapbuf)==0) {
  367.                 printDpmiException(module);
  368.             }
  369.             Dpmi.fail("Processor Exception encountered\n");
  370.             break;
  371.         }
  372.         case 2:
  373.         {
  374.             Dpmi.fail("Control-C intercepted\n");
  375.             break;
  376.         }
  377.  
  378.         default:
  379.             break;
  380.     }
  381.     return 0;
  382. }
  383.  
  384.  
  385.  
  386. //=====================================================================
  387. //
  388. //  main
  389. //
  390. //  We switch to protected mode, and call the protected mode mainline
  391. //
  392. //=====================================================================
  393. int main(int argc, char *argv[], char *envp[])
  394. {
  395.     int ret;
  396.     
  397.     flushall();     // flush all buffers before switch into protected mode, 
  398.                     // so I/O redirection works properly
  399.  
  400.     if (!Dpmi.present())
  401.       if (!Dpmi.init())
  402.         Dpmi.fail("This program requires DPMI");
  403.  
  404.     // now in protected mode: segment registers have changed
  405.  
  406.  
  407.     ret = protectedMain(argc, argv, envp);
  408.  
  409.     flushall();
  410.  
  411.     Dpmi.dosExit(ret);
  412.  
  413.     return 0;
  414. }
  415.  
  416.